package com.plian.system.service.im.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.plian.Tools.*;
import com.plian.Tools.pagedata.PageData;
import com.plian.system.common.status.CheckStatus;
import com.plian.system.common.status.CustomCode;
import com.plian.system.constant.baseinfo.ValueSetConstant;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.constant.sys.FormTypeConstant;
import com.plian.system.constant.yth.YthConstant;
import com.plian.system.dao.sys.orgzation.OrgzationDao;
import com.plian.system.dto.im.BaseInvestmentExecutionDTO;
import com.plian.system.entity.im.BaseInvestmentExecution;
import com.plian.system.entity.im.EffectiveInvestment;
import com.plian.system.entity.im.FundProject;
import com.plian.system.entity.im.MainProjectSituation;
import com.plian.system.entity.sys.ApprovalMessage;
import com.plian.system.enumeratea.CheckName;
import com.plian.system.mapper.im.BaseInvestmentExecutionMapper;
import com.plian.system.mapper.im.BaseInvestmentPlanMapper;
import com.plian.system.mapper.im.MainProjectSituationMapper;
import com.plian.system.model.CommonCode;
import com.plian.system.model.R;
import com.plian.system.mybatis.base.BaseFlowService;
import com.plian.system.mybatis.base.BaseServiceImpl;
import com.plian.system.service.bt.baseinfo.BaseInfoService;
import com.plian.system.service.im.IBaseInvestmentExecutionService;
import com.plian.system.service.im.IEffectiveInvestmentService;
import com.plian.system.service.im.IFundProjectService;
import com.plian.system.service.sys.code.IFormCodeService;
import com.plian.system.service.sys.message.IApprovalMessageService;
import com.plian.system.service.sys.orgzation.IOrgService;
import com.plian.system.service.wf.FormWorkflowService;
import com.plian.system.vo.im.*;
import com.plian.system.vo.report.ChartsVO;
import com.plian.system.vo.report.LegendVO;
import com.plian.system.vo.report.SeriesVO;
import com.plian.system.vo.report.XAxisVO;
import com.plian.system.vo.yth.YthResult;
import com.plian.system.wrapper.im.BaseInvestmentExecutionWrapper;
import com.plian.system.wrapper.im.EffectiveInvestmentWrapper;
import com.plian.system.wrapper.im.FundProjectWrapper;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.plian.system.constant.sys.ApprovalMessageTypeConstant.INVESTMENT_EXECUTION;
import static com.plian.system.constant.sys.ApprovalMessageTypeConstant.KT_TYPE;
import static com.plian.system.constant.sys.FormStatusConstant.UNREVIEWED;

/**
 * 服务实现类
 *
 * @author
 * @since 2019-09-27
 */
@Service
@AllArgsConstructor
public class BaseInvestmentExecutionServiceImpl extends BaseServiceImpl<BaseInvestmentExecutionMapper, BaseInvestmentExecution> implements IBaseInvestmentExecutionService, BaseFlowService {

	private FormWorkflowService formWorkflowService;

	private BaseInvestmentPlanMapper baseInvestmentPlanMapper;

	private MainProjectSituationMapper mainProjectSituationMapper;

	private IEffectiveInvestmentService effectiveInvestmentService;

	private IFundProjectService fundProjectService;

	private Environment environment;

	private IFormCodeService formCodeService;

	private BaseInfoService baseInfoService;

	private OrgzationDao orgzationDao;

	private BaseInvestmentExecutionWrapper baseInvestmentExecutionWrapper;

	private EffectiveInvestmentWrapper effectiveInvestmentWrapper;

	private FundProjectWrapper fundProjectWrapper;

	private IApprovalMessageService approvalMessageService;

	private IOrgService orgService;
	/**
	 * logger属性.
	 */
	private static final Logger LOGGER  = LoggerFactory.getLogger(BaseInvestmentExecutionServiceImpl.class);

	@Override
	public boolean saveOrUpdate(BaseInvestmentExecution baseInvestmentExecution) {

		if (!Optional.ofNullable(baseInvestmentExecution.getStatus()).isPresent()) {
			baseInvestmentExecution.setStatus(FormStatusConstant.UNREVIEWED);
		}
		if (!Optional.ofNullable(baseInvestmentExecution.getId()).isPresent()) {
			baseInvestmentExecution.setCode(formCodeService.getCode(FormTypeConstant.IM_BASE_INVESTMENT_EXECUTION_FORM_OLD));
			baseInvestmentExecution.setFormType(String.valueOf(FormTypeConstant.IM_BASE_INVESTMENT_EXECUTION_FORM_OLD));
		}
		return super.saveOrUpdate(baseInvestmentExecution);
	}

	@Override
	@Transactional(rollbackFor=RuntimeException.class)
	public boolean deleteLogic(List<Long> ids) {
		for (Long id : ids) {
			BaseInvestmentExecution baseInvestmentExecution = getById(id);
			if (baseInvestmentExecution == null) {
				return false;
			} else if (baseInvestmentExecution.getStatus() != null &&
					(baseInvestmentExecution.getStatus() != FormStatusConstant.STASH && baseInvestmentExecution.getStatus() != FormStatusConstant.UNREVIEWED)) {
				return false;
			}
			formWorkflowService.deleteProcessInstance(String.valueOf(id));
		}

		boolean result = super.deleteLogic(ids);
		if (result){
			effectiveInvestmentService.deleteByParentId(ids);
			fundProjectService.deleteByParentId(ids);
		}
		return result;
	}

	@Override
	public HashMap<String,Object> commit(String id) {
		handleStatus(Long.valueOf(id), FormStatusConstant.FLOW, null);

		//将需要提交的流程变量返回，用于工作流侧
		return new HashMap<String,Object>();
	}

	@Override
	public Boolean finish(String id) {
		return handleStatus(Long.valueOf(id), FormStatusConstant.FINISH, "审批通过");
	}

	@Override
	public Boolean reject(String id, int formState, String comment) {
		return handleStatus(Long.valueOf(id), formState, comment);
	}


	/**
	 * 统一处理状态机事件方法
	 *
	 * @param id          主键
	 * @param updateStatus  更新状态
	 * @return boolean
	 */
	private Boolean handleStatus(Long id, int updateStatus, String comment) {
		try {
			BaseInvestmentExecution baseInvestmentExecution = getById(id);
			/**
			 * 设置审批人和审批时间
			 */
			if (updateStatus == FormStatusConstant.FINISH){
				baseInvestmentExecution.setApprovedUser(TokenUtil.getTokenUserId());
				Date now = DateUtil.now();
				baseInvestmentExecution.setApprovedTime(now);
			}
			if (StringUtil.isNotBlank(baseInvestmentExecution.getDataSource()) &&
					StringUtil.isNotBlank(baseInvestmentExecution.getDataSourceId())
					&& !YthConstant.DATA_NINGBO.equals(baseInvestmentExecution.getDataSource())){
				if (updateStatus == FormStatusConstant.FINISH || updateStatus == FormStatusConstant.REJECT){
					ApprovalMessage approvalMessage = new ApprovalMessage();
					approvalMessage.setDataSourceId(baseInvestmentExecution.getDataSourceId());
					approvalMessage.setType(INVESTMENT_EXECUTION);
					approvalMessage.setOpinion(comment);
					approvalMessage.setIsApprove(updateStatus == FormStatusConstant.FINISH ? 2 : 1);
					approvalMessage.setIsSend(1);
					approvalMessage.setDataSourceType(KT_TYPE);
					approvalMessage.setFilingCode(baseInvestmentExecution.getCode());
					approvalMessageService.save(approvalMessage);
				}
			}
			baseInvestmentExecution.setStatus(updateStatus);
			updateById(baseInvestmentExecution);
			return true;
		} catch (Exception e) {
			log.error(ExceptionUtils.getFullStackTrace(e));
			return false;
		}
	}


	@Override
	public List<PageData> findByIds(List<String> formIds) {
		LambdaQueryWrapper<BaseInvestmentExecution> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.in(BaseInvestmentExecution::getId, Func.toLongList(StringUtils.join(formIds, StringPool.COMMA)));
		List<BaseInvestmentExecution> baseInvestmentExecutions = list(queryWrapper);
		List<BaseInvestmentExecutionVO> baseInvestmentExecutionVOS= baseInvestmentExecutionWrapper.entityToVO(baseInvestmentExecutions);
		List<PageData> pageDataList = new ArrayList<>();
		try{
			if (CollectionUtil.isNotEmpty(baseInvestmentExecutionVOS)){
				for (BaseInvestmentExecutionVO vo : baseInvestmentExecutionVOS){
					PageData pd = new PageData();
					pd.put("id", vo.getId());
					pd.put("UNITNAME", vo.getFilingUnitName());
					pd.put("APPLICANTNAME", vo.getCreateUserName());
					pd.put("applicantId", vo.getCreateUser());
					pd.put("applyOrganizationId", vo.getFilingUnitId());
					pd.put("formType", FormTypeConstant.IM_BASE_INVESTMENT_EXECUTION_FORM_OLD);
					pd.put("orgName", vo.getFilingUnitName());
					pageDataList.add(pd);
				}
			}

			return pageDataList;
		} catch (Exception e) {
			log.error(ExceptionUtils.getFullStackTrace(e));
		}
		return pageDataList;
	}

	@Override
	public List<Integer> getFormType() {
		return Collections.singletonList(FormTypeConstant.IM_BASE_INVESTMENT_EXECUTION_FORM_OLD);
	}

	@Override
	@Transactional(rollbackFor=RuntimeException.class)
	public boolean submit(BaseInvestmentExecution baseInvestmentExecution) {
		boolean result = saveOrUpdate(baseInvestmentExecution);
		if (result){
			EffectiveInvestment effectiveInvestment = baseInvestmentExecution.getEffectiveInvestment();
			if (Optional.ofNullable(effectiveInvestment).isPresent()){
				if (effectiveInvestment.getId() != null &&
						Optional.ofNullable(effectiveInvestment.getIsDeleted()).isPresent() && effectiveInvestment.getIsDeleted().intValue() == 1) {
					effectiveInvestmentService.removeById(effectiveInvestment.getId());
				}else {
					effectiveInvestment.setBaseInvestmentExecutionId(baseInvestmentExecution.getId());
					effectiveInvestmentService.submit(effectiveInvestment);
				}
			}

			List<FundProject> fundProjects = baseInvestmentExecution.getFundProjects();
			if (CollectionUtil.isNotEmpty(fundProjects)){
				for (FundProject fundProject : fundProjects){
					if (fundProject.getId() != null &&
							Optional.ofNullable(fundProject.getIsDeleted()).isPresent() && fundProject.getIsDeleted().intValue() == 1) {
						fundProjectService.removeById(fundProject.getId());
					}else {
						fundProject.setBaseInvestmentExecutionId(baseInvestmentExecution.getId());
						fundProjectService.submit(fundProject);
					}
				}
			}
		}

		return result;
	}

	@Override
	public R<BaseInvestmentExecutionVO> getDetailObj(BaseInvestmentExecutionVO baseInvestmentExecutionVO) {
		if(!Optional.ofNullable(baseInvestmentExecutionVO).isPresent()){
			return new R(CommonCode.FAIL);
		}

		R<BaseInvestmentExecutionVO> objResult = new R<>(CommonCode.SUCCESS);
		EffectiveInvestmentVO effectiveInvestmentVO = effectiveInvestmentWrapper.entityToVO(
				effectiveInvestmentService.getOne(new LambdaQueryWrapper<EffectiveInvestment>()
						.eq(EffectiveInvestment::getBaseInvestmentExecutionId, baseInvestmentExecutionVO.getId())));
		baseInvestmentExecutionVO.setEffectiveInvestmentVO(effectiveInvestmentService.getDetailPd(effectiveInvestmentVO));
		List<FundProjectVO> fundProjectVOS = fundProjectWrapper.entityToVO(fundProjectService.list(new LambdaQueryWrapper<FundProject>()
				.eq(FundProject::getBaseInvestmentExecutionId, baseInvestmentExecutionVO.getId())));
		baseInvestmentExecutionVO.setFundProjectVOS(fundProjectService.getDetailPd(fundProjectVOS));
		objResult.setPageData(baseInvestmentExecutionVO);
		return objResult;
	}


	@Override
	public String checkMonth(BaseInvestmentExecution baseInvestmentExecution) {
		LambdaQueryWrapper<BaseInvestmentExecution> queryWrapper = new LambdaQueryWrapper<>();
		if (!Optional.ofNullable(baseInvestmentExecution.getFilingMonth()).isPresent()) {
			return "填报时间为空";
		}
		if (!Optional.ofNullable(baseInvestmentExecution.getFilingUnitId()).isPresent()){
			return "填报单位为空";
		}
		queryWrapper.eq(BaseInvestmentExecution::getFilingUnitId,baseInvestmentExecution.getFilingUnitId());
		queryWrapper.eq(BaseInvestmentExecution::getFilingMonth, baseInvestmentExecution.getFilingMonth());
		BaseInvestmentExecution one = getOne(queryWrapper);
		if (!Optional.ofNullable(one).isPresent()){
			return null;
		}
		if (one.getId().equals(baseInvestmentExecution.getId())){
			return null;
		}
		return "该月份已填报";
	}
	@Override
	public String export(Long baseInvestmentExecutionId) {

		String key = baseInvestmentExecutionId + StringPool.DASH + UUID.randomUUID().toString().replace(StringPool.DASH, "");
		String fileName = key + ".xlsx";
		String exportPath = environment.getProperty("excel.path");
		LOGGER.info("BaseInvestmentExecutionServiceImpl baseInvestmentExecutionId--exportPath--->"  + exportPath);
		/**
		 * 导出路径不存在则创建
		 */
		File file = new File(exportPath);
		if (!file.exists()) {
			file.mkdirs();
		}
		InputStream inputStream = this.getClass().getResourceAsStream("/exceldemo/investmentExecution.xlsx");
		ExcelWriter excelWriter = EasyExcel.write(exportPath + fileName).withTemplate(inputStream).build();

		// 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行，然后下面的数据往后移动。默认 是false，会直接使用下一行，如果没有则创建。
		// forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了，所以慎用
		// 简单的说 如果你的模板有list,且list不是最后一行，下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存

		FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();

		// 表一
		WriteSheet effectiveInvestmentWriteSheet = EasyExcel.writerSheet(0).build();
		EffectiveInvestment effectiveInvestment = effectiveInvestmentService.getOne(new LambdaQueryWrapper<EffectiveInvestment>()
				.eq(EffectiveInvestment::getBaseInvestmentExecutionId, baseInvestmentExecutionId));
		if (null==effectiveInvestment){
			effectiveInvestment = new EffectiveInvestment();
		}
		effectiveInvestmentService.write(effectiveInvestment, excelWriter, effectiveInvestmentWriteSheet, fillConfig);

//		// 表二
//		WriteSheet fundProjectWriteSheet = EasyExcel.writerSheet(1).build();
//		List<FundProject> fundProjects = fundProjectService.list(new QueryWrapper<FundProject>().eq("base_investment_execution_id", baseInvestmentExecutionId));
//		Map<String, String> projectMap =baseInfoService.getChildMap(ValueSetConstant.FUND_CATEGORY);
//		for (FundProject fundProject : fundProjects) {
//			fundProject.setFundCategory(projectMap.get(fundProject.getFundCategory()));
//		}
//		fundProjectService.write(fundProjects, excelWriter, fundProjectWriteSheet, fillConfig);
		BaseInvestmentExecutionVO baseInvestmentExecutionVO = baseInvestmentExecutionWrapper.entityToVO(getById(baseInvestmentExecutionId));

		// 其他参数可以使用Map封装
		Map<String, Object> otherMap = new HashMap<>(16);
		otherMap.put("filingUnitName", baseInvestmentExecutionVO.getFilingUnitName());
		otherMap.put("filingMonth", baseInvestmentExecutionVO.getFilingMonth());

		excelWriter.fill(otherMap, effectiveInvestmentWriteSheet);
		//excelWriter.fill(otherMap, fundProjectWriteSheet);
		excelWriter.finish();
		return key;
	}

	@Override
	public void download(String key, HttpServletResponse response, OutputStream os) {
		Long baseInvestmentPlanId = Long.valueOf(key.split(StringPool.DASH)[0]);
		BaseInvestmentExecutionVO baseInvestmentDebtVO = baseInvestmentExecutionWrapper.entityToVO(getById(baseInvestmentPlanId));
		String excelName = baseInvestmentDebtVO.getFilingMonth() + "_项目投资计划_" +  baseInvestmentDebtVO.getFilingUnitName();
		String excelPath = environment.getProperty("excel.path") + "/" + key + ".xlsx";

		try {
			os = response.getOutputStream();//取得输出流
			response.reset();//清空输出流
			//下面是对中文文件名的处理
			response.setCharacterEncoding("UTF-8");//设置相应内容的编码格式

			InputStream inputStream = new FileInputStream(excelPath);
			excelName = java.net.URLEncoder.encode(excelName, "UTF-8");
			response.setHeader("Content-Disposition", "attachment;filename=" + new String(excelName.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8) + ".xlsx");

			response.setContentType("application/msexcel");//定义输出类型
			int len;
			byte[] b = new byte[2048];
			while ((len = inputStream.read(b)) != -1) {
				os.write(b, 0, len);
			}
			response.setHeader("Content-Length", String.valueOf(inputStream.available()));

			inputStream.close();
			os.close();
		}catch (Exception e){
			log.error(ExceptionUtils.getFullStackTrace(e));
		}finally {
			/**
			 * 删除文件
			 */
			File file = new File(excelPath);
			if(file.exists() && file.isFile()){
				file.delete();
			}
		}
	}

	@Override
	public void goBackToStash(String formId) {
		handleStatus(Long.valueOf(formId), UNREVIEWED, null);
	}

	@Override
	public R<BaseInvestmentExecutionVO> getLastMonthObj(BaseInvestmentExecution baseInvestmentExecution) {
		String filingMonth = baseInvestmentExecution.getFilingMonth();
		Calendar c = Calendar.getInstance();
		c.setTime(DateUtil.parse(filingMonth, DateUtil.PATTERN_MONTH));
		c.add(Calendar.MONTH, -1);
		String lastMonth = DateUtil.format(c.getTime(), DateUtil.PATTERN_MONTH);
		BaseInvestmentExecution last = getOne(new LambdaQueryWrapper<BaseInvestmentExecution>()
				.eq(BaseInvestmentExecution::getFilingUnitId, baseInvestmentExecution.getFilingUnitId())
				.eq(BaseInvestmentExecution::getFilingMonth, lastMonth));
		BaseInvestmentExecutionVO baseInvestmentExecutionVO = new BaseInvestmentExecutionVO();
		if (Optional.ofNullable(last).isPresent()){
			EffectiveInvestment effectiveInvestment = effectiveInvestmentService.getOne(
					new LambdaQueryWrapper<EffectiveInvestment>().eq(EffectiveInvestment::getBaseInvestmentExecutionId, last.getId()));
			baseInvestmentExecutionVO.setEffectiveInvestmentVO(effectiveInvestmentService.getLastMainInfos(effectiveInvestment.getId()));

			List<FundProjectVO> fundProjectVOS = fundProjectWrapper.entityToVO(fundProjectService.list(new LambdaQueryWrapper<FundProject>()
					.eq(FundProject::getBaseInvestmentExecutionId, last.getId())));
			baseInvestmentExecutionVO.setFundProjectVOS(fundProjectService.getLastMonthInfos(fundProjectVOS));
		}else {
			return new R(CustomCode.builder().message("上月无数据！").code(1999).success(false).build());
		}

		R objResult = new R(CommonCode.SUCCESS);
		objResult.setPageData(baseInvestmentExecutionVO);
		return objResult;
	}

	@Override
	public ChartsVO statisticsCompanyProportion(BaseInvestmentExecutionDTO baseInvestmentExecutionDTO) {
		try {
			String orgId = baseInvestmentExecutionDTO.getOrgId();
			if (StringUtil.isNotBlank(orgId)) {
				PageData org = orgzationDao.findbyid(orgId);
				if (org != null && !"0".equals(org.getString("parentId"))) {
					List<String> fillingUnitIds = new ArrayList<>();
					fillingUnitIds.add(orgId);
					baseInvestmentExecutionDTO.setFillingUnitIds(fillingUnitIds);
				}
			}
		}catch (Exception e){
			LOGGER.error(String.valueOf(e));
		}

		List<InvestmentMonthSummaryVO> results = effectiveInvestmentService.summary(baseInvestmentExecutionDTO);

		if (CollectionUtil.isEmpty(results)){
			return null;
		}


		List<String> data = new ArrayList<>();
		data.add("完成率");
		LegendVO legendVO = LegendVO.builder().data(data).build();

		List<XAxisVO> xAxisVOS = new ArrayList<>();
		List<String> xList = new ArrayList<>();
		List<Object> companyProportionList = new ArrayList<>();
//		List<Object> planInvestmentTotalList = new ArrayList<>();
//		List<Object> allCompleteInvestmentList = new ArrayList<>();
		List<String> ids = new ArrayList<>();

		BigDecimal  endPlanInvestmentTotal = new BigDecimal(0);
		BigDecimal  endAllCompleteInvestmentList = new BigDecimal(0);
		for (int i = 0; i < results.size()-1; i++){
			InvestmentMonthSummaryVO result = results.get(i);
			if (StringUtil.isNotBlank(CheckName.getAbbreviationName(result.getUnitCheck()))){
				xList.add(CheckName.getAbbreviationName(result.getUnitCheck()));
			}else {
				xList.add(result.getUnitCheck());
			}
//			planInvestmentTotalList.add(result.getPlanInvestmentTotal() != null ? result.getPlanInvestmentTotal() : 0);
//			allCompleteInvestmentList.add(result.getAllCompleteInvestment() != null ? result.getAllCompleteInvestment() : 0);
			companyProportionList.add(result.getCompleteProportion() != null ? result.getCompleteProportion() : 0 + StringPool.PERCENT);
			ids.add(result.getFilingUnitId());

			endPlanInvestmentTotal = BigDecimalUtil.add(endPlanInvestmentTotal, result.getPlanInvestmentTotal());
			endAllCompleteInvestmentList = BigDecimalUtil.add(endAllCompleteInvestmentList, result.getAllCompleteInvestment());
		}

		BigDecimal endCompanyProportion = BigDecimalUtil.divide(endAllCompleteInvestmentList, endPlanInvestmentTotal, 2, BigDecimal.ROUND_HALF_UP, 100);
		List<SeriesVO> seriesVOS = new ArrayList<>();
//		seriesVOS.add(SeriesVO.builder().name("计划投资额").type("bar").data(planInvestmentTotalList).build());
//		seriesVOS.add(SeriesVO.builder().name("完成投资额").type("bar").data(allCompleteInvestmentList).build());
		seriesVOS.add(SeriesVO.builder().name("完成率").type("bar").data(companyProportionList).build());
		xAxisVOS.add(XAxisVO.builder().data(xList).build());

		List<String> total = new ArrayList<>();
		total.add("总计划投资额: " + BigDecimalUtil.divide(endPlanInvestmentTotal, new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP) + "亿元");
		total.add("累计实际投资额: " + BigDecimalUtil.divide(endAllCompleteInvestmentList, new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP) + "亿元");
		total.add("完成率: " + endCompanyProportion + StringPool.PERCENT);
		ChartsVO chartsVO = ChartsVO.builder().legend(legendVO).ids(ids)
				.xAxis(xAxisVOS).series(seriesVOS).total(total).build();
		return chartsVO;
	}

	@Override
	public ChartsVO statisticsCompany(BaseInvestmentExecutionDTO baseInvestmentExecutionDTO) {
		/**
		 * 填报年度为空时默认为当前年度
		 */
		String filingYear = baseInvestmentExecutionDTO.getFilingYear();
		if (StringUtil.isBlank(filingYear)){
			filingYear = DateUtil.format(DateUtil.now(), DateUtil.PATTERN_YEAR);
		}


		List<BaseInvestmentExecution> results = baseMapper.queryByYear(baseInvestmentExecutionDTO.getFilingUnitId(), filingYear);
		if (CollectionUtil.isEmpty(results)){
			return null;
		}

		InvestmentUnitSummaryVO planSummary = baseInvestmentPlanMapper.summaryPlanInvestment(filingYear, baseInvestmentExecutionDTO.getFilingUnitId());

		List<String> data = new ArrayList<>();
		data.add("股权投资");
		data.add("固定资产投资");
		data.add("重点项目");
		data.add("完成率");
		LegendVO legendVO = LegendVO.builder().data(data).build();

		List<XAxisVO> xAxisVOS = new ArrayList<>();
		List<String> xList = new ArrayList<>();

		List<Object> fixedList = new ArrayList<>();
		List<Object> stakeList = new ArrayList<>();
		List<Object> mainList = new ArrayList<>();
		List<Object> companyProportionList = new ArrayList<>();
		List<String> ids = new ArrayList<>();
		for (BaseInvestmentExecution baseInvestmentExecution : results){
			String month = Integer.valueOf(baseInvestmentExecution.getFilingMonth().split(StringPool.DASH)[1]) + "月";
			xList.add(month);
			BigDecimal fixedInvestment = new BigDecimal(0);
			BigDecimal stakeInvestment = new BigDecimal(0);
			BigDecimal mainInvestment = new BigDecimal(0);
			EffectiveInvestment effectiveInvestment = baseInvestmentExecution.getEffectiveInvestment();
			if (Optional.ofNullable(effectiveInvestment).isPresent()){
				fixedInvestment = BigDecimalUtil.add(fixedInvestment, effectiveInvestment.getAllCompleteFixedInvestment());
				stakeInvestment = BigDecimalUtil.add(stakeInvestment, effectiveInvestment.getAllCompleteEquityInvestment());
				if( CollectionUtil.isNotEmpty(baseInvestmentExecution.getEffectiveInvestment().getMainProjectSituations())){
					for (MainProjectSituation mainProjectSituation :
							baseInvestmentExecution.getEffectiveInvestment().getMainProjectSituations()){
						mainInvestment = BigDecimalUtil.add(mainInvestment, mainProjectSituation.getLastCompleteInvestment());
						mainInvestment = BigDecimalUtil.add(mainInvestment, mainProjectSituation.getCompleteInvestment());
					}
				}
			}

			if (baseInvestmentExecutionDTO.getUnitType() != null && baseInvestmentExecutionDTO.getUnitType() == 2) {
				fixedList.add(fixedInvestment != null ? BigDecimalUtil.divide(fixedInvestment, new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP) : 0);
				stakeList.add(stakeInvestment != null ? BigDecimalUtil.divide(stakeInvestment, new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP) : 0);
				mainList.add(mainInvestment != null ? BigDecimalUtil.divide(mainInvestment, new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP) : 0);
			}else {
				fixedList.add(fixedInvestment != null ? fixedInvestment : 0);
				stakeList.add(stakeInvestment != null ? stakeInvestment : 0);
				mainList.add(mainInvestment != null ? mainInvestment : 0);
			}

			if (Optional.ofNullable(planSummary).isPresent()){
				companyProportionList.add(BigDecimalUtil.divide(BigDecimalUtil.add(fixedInvestment, stakeInvestment),
						planSummary.getInvestment(), 2, BigDecimal.ROUND_HALF_UP, 100));
			}
			ids.add(String.valueOf(baseInvestmentExecution.getId()));

		}

		List<SeriesVO> seriesVOS = new ArrayList<>();
		seriesVOS.add(SeriesVO.builder().name("股权投资").type("bar").data(fixedList).build());
		seriesVOS.add(SeriesVO.builder().name("固定资产投资").type("bar").data(stakeList).build());
		seriesVOS.add(SeriesVO.builder().name("重点项目").type("bar").data(mainList).build());
		seriesVOS.add(SeriesVO.builder().name("完成率").yAxisIndex(1).type("line").data(companyProportionList).build());

		xAxisVOS.add(XAxisVO.builder().data(xList).build());
		ChartsVO chartsVO = ChartsVO.builder().legend(legendVO).ids(ids)
				.xAxis(xAxisVOS).series(seriesVOS).build();
		return chartsVO;
	}

	@Override
	public ChartsVO statisticsProjectNature(BaseInvestmentExecutionDTO baseInvestmentExecutionDTO) {
		/**
		 * 填报年月为空时默认为当前月份
		 */
		String filingMonth = baseInvestmentExecutionDTO.getFilingMonth();
		if (StringUtil.isBlank(filingMonth)){
			filingMonth = DateUtil.format(DateUtil.now(), DateUtil.PATTERN_MONTH);
		}

		List<MainProjectSituation> mainProjectSituations = mainProjectSituationMapper.queryByMonth(filingMonth, filingMonth.split(StringPool.DASH)[0]);
		if (CollectionUtil.isEmpty(mainProjectSituations)){
			return null;
		}

		List<String> data = new ArrayList<>();
		data.add("完成率");
		LegendVO legendVO = LegendVO.builder().data(data).build();

		List<XAxisVO> xAxisVOS = new ArrayList<>();
		List<String> xList = new ArrayList<>();
		List<Object> companyProportionList = new ArrayList<>();
		List<String> ids = new ArrayList<>();

		Map<String, List<MainProjectSituation>> resultMap = mainProjectSituations.stream()
				.collect(Collectors.groupingBy(MainProjectSituation::getProjectNatureId));
		Map<String, String> projectMap = baseInfoService.getChildMap(ValueSetConstant.PROJECT_NATURE);
		List<String> keys = projectMap.keySet().stream().filter(key -> !Stream.of("070001","070002","070003","070004","070005","070006")
						.collect(Collectors.toList()).contains(key)).collect(Collectors.toList());
		Set<String> projectNatureIdSet = new TreeSet<>(Comparator.naturalOrder());
		projectNatureIdSet.addAll(keys);

		List<Long> userProjectIds = new ArrayList<>();
		projectNatureIdSet.forEach(projectNatureId -> {
			ids.add(projectNatureId);
			xList.add(projectMap.get(projectNatureId));
			boolean flag = true;
			if (resultMap.containsKey(projectNatureId)){
				BigDecimal planInvestment = new BigDecimal(0);
				BigDecimal completeInvestment = new BigDecimal(0);
				for (MainProjectSituation mainProjectSituation : resultMap.get(projectNatureId)){
					if (!userProjectIds.contains(mainProjectSituation.getProjectId())){
						planInvestment = BigDecimalUtil.add(planInvestment, mainProjectSituation.getPlanTotalInvestment());
						userProjectIds.add(mainProjectSituation.getProjectId());
					}
					completeInvestment = BigDecimalUtil.add(completeInvestment, mainProjectSituation.getCompleteInvestment());
					completeInvestment = BigDecimalUtil.add(completeInvestment, mainProjectSituation.getLastCompleteInvestment());
				}
				BigDecimal companyProportion = BigDecimalUtil.divide(completeInvestment, planInvestment, 2, BigDecimal.ROUND_HALF_UP, 100);
				companyProportionList.add(companyProportion != null ? companyProportion : 0);
			}else {
				companyProportionList.add(new BigDecimal(0));
			}
		});

		List<SeriesVO> seriesVOS = new ArrayList<>();
		seriesVOS.add(SeriesVO.builder().name("完成率").type("bar").data(companyProportionList).build());
		xAxisVOS.add(XAxisVO.builder().data(xList).build());
		ChartsVO chartsVO = ChartsVO.builder().legend(legendVO).ids(ids)
				.xAxis(xAxisVOS).series(seriesVOS).build();
		return chartsVO;
	}

//	@Override TODO DEL
//	public ChartsVO statisticsMainProject(BaseInvestmentExecutionDTO baseInvestmentExecutionDTO) {
//		/**
//		 * 填报年月为空时默认为当前月份
//		 */
//		String filingMonth = baseInvestmentExecutionDTO.getReportTime();
//		if (StringUtil.isBlank(filingMonth)){
//			filingMonth = DateUtil.format(DateUtil.now(), DateUtil.PATTERN_MONTH);
//		}
//
//		List<String> fillingUnitIds = new ArrayList<>();
//		boolean flag = false;
//		String orgId = baseInvestmentExecutionDTO.getOrgId();
//		if (Optional.ofNullable(orgId).isPresent()){
//			try {
//				PageData org = orgzationDao.findbyid(orgId);
//				if (!"0".equals(org.getString("parentId"))) {
//					fillingUnitIds.add(orgId);
//					flag = true;
//				}
//			}catch (Exception e){
//				log.error("statisticsMainProject---->获取单位失败");
//			}
//
//
//		}
//		List<MainProjectSummaryVO> results;
//		if(flag){
//			//单个企业 按项目类型
//			results = mainProjectSituationMapper.projectNatureSummaryByMonth(orgId, filingMonth, filingMonth.split(StringPool.DASH)[0]);
//		}else {
//			//国资委 按单位统计
//			results = mainProjectSituationMapper.summaryByMonth(fillingUnitIds, filingMonth, filingMonth.split(StringPool.DASH)[0]);
//		}
//
//		if (CollectionUtil.isEmpty(results)){
//			return null;
//		}
//
//		List<String> data = new ArrayList<>();
//		data.add("计划投资额");
//		data.add("实际投资额");
//		data.add("完成率");
//		LegendVO legendVO = LegendVO.builder().data(data).build();
//
//		List<XAxisVO> xAxisVOS = new ArrayList<>();
//		List<String> xList = new ArrayList<>();
//		List<Object> planTotalInvestmentList = new ArrayList<>();
//		List<Object> completeInvestmentList = new ArrayList<>();
//		List<Object> completeProportionList = new ArrayList<>();
//
//		BigDecimal endPlanTotalInvestment = new BigDecimal(0);
//		BigDecimal endCompleteInvestment = new BigDecimal(0);
//		for (MainProjectSummaryVO mainProjectSummaryVO : results){
//			if (StringUtil.isNotBlank(CheckName.getAbbreviationName(mainProjectSummaryVO.getUnitCheck()))){
//				xList.add(CheckName.getAbbreviationName(mainProjectSummaryVO.getUnitCheck()));
//			}else {
//				xList.add(mainProjectSummaryVO.getUnitCheck());
//			}
//			planTotalInvestmentList.add(mainProjectSummaryVO.getPlanTotalInvestment() != null ?
//					BigDecimalUtil.divide(mainProjectSummaryVO.getPlanTotalInvestment(), new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP) : 0);
//			completeInvestmentList.add(mainProjectSummaryVO.getCompleteInvestment() != null ?
//					BigDecimalUtil.divide(mainProjectSummaryVO.getCompleteInvestment(), new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP) : 0);
//			endPlanTotalInvestment = BigDecimalUtil.add(endPlanTotalInvestment, mainProjectSummaryVO.getPlanTotalInvestment());
//			endCompleteInvestment = BigDecimalUtil.add(endCompleteInvestment, mainProjectSummaryVO.getCompleteInvestment());
//			completeProportionList.add(BigDecimalUtil.divide(mainProjectSummaryVO.getCompleteInvestment(), mainProjectSummaryVO.getPlanTotalInvestment(),
//					2, BigDecimal.ROUND_HALF_UP,  100) + "%");
//		}
//
//		List<SeriesVO> seriesVOS = new ArrayList<>();
//		seriesVOS.add(SeriesVO.builder().name("计划投资额").type("bar").data(planTotalInvestmentList).build());
//		seriesVOS.add(SeriesVO.builder().name("实际投资额").type("bar").data(completeInvestmentList).build());
//		seriesVOS.add(SeriesVO.builder().name("完成率").type("bar").data(completeProportionList).build());
//		xAxisVOS.add(XAxisVO.builder().data(xList).build());
//
//		List<String> total = new ArrayList<>();
//		total.add("重点项目计划总投资: " + BigDecimalUtil.divide(endPlanTotalInvestment, new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP) + "亿元");
//		total.add("累计实际投资额: " + BigDecimalUtil.divide(endCompleteInvestment, new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP) + "亿元");
//		total.add("完成率: " + BigDecimalUtil.divide(endCompleteInvestment, endPlanTotalInvestment, 2, BigDecimal.ROUND_HALF_UP,  100) + "%");
//		ChartsVO chartsVO = ChartsVO.builder().legend(legendVO)
//				.xAxis(xAxisVOS).series(seriesVOS).total(total)
//				.build();
//		return chartsVO;
//	}

//	@Override TODO DEL
//	public BigDecimal completeProportion(boolean isGZW, String fillingMonth, String orgId) {
//		BaseInvestmentExecutionDTO baseInvestmentExecutionDTO = new BaseInvestmentExecutionDTO();
//		List<String> fillingUnitIds = new ArrayList<>();
//		if (!isGZW){
//			fillingUnitIds.add(orgId);
//		}
//		baseInvestmentExecutionDTO.setFilingMonth(fillingMonth);
//		baseInvestmentExecutionDTO.setFillingUnitIds(fillingUnitIds);
//		List<InvestmentMonthSummaryVO> results = effectiveInvestmentService.summary(baseInvestmentExecutionDTO);
//		BigDecimal endPlanInvestmentTotal = new BigDecimal(0);
//		BigDecimal endAllCompleteInvestmentList = new BigDecimal(0);
//		if (CollectionUtil.isNotEmpty(results)){
//			for (int i = 0; i < results.size()-1; i++){
//				InvestmentMonthSummaryVO result = results.get(i);
//				endPlanInvestmentTotal = BigDecimalUtil.add(endPlanInvestmentTotal, result.getPlanInvestmentTotal());
//				endAllCompleteInvestmentList = BigDecimalUtil.add(endAllCompleteInvestmentList, result.getAllCompleteInvestment());
//			}
//
//		}
//		BigDecimal endCompanyProportion = BigDecimalUtil.divide(endAllCompleteInvestmentList, endPlanInvestmentTotal, 2, BigDecimal.ROUND_HALF_UP, 100);
//		if(!Optional.ofNullable(endCompanyProportion).isPresent()){
//			endCompanyProportion = new BigDecimal(0);
//		}
//		return endCompanyProportion;
//	}

	@Override
	public EffectiveInvestmentVO statisticsProjectByCompany(BaseInvestmentExecutionDTO baseInvestmentExecutionDTO) {
		List<ExecutionProjectSituationVO> dataList = baseMapper.queryExecutionProjectByMonth(baseInvestmentExecutionDTO.getFillingUnitIds(), baseInvestmentExecutionDTO.getFillingMonth());
		if (CollectionUtil.isEmpty(dataList)){
			return EffectiveInvestmentVO.builder().fixedProjectSituationVOS(new ArrayList<>()).stakeProjectSituationVOS(new ArrayList<>()).build();
		}

		EffectiveInvestmentVO result = new EffectiveInvestmentVO();
		Map<Integer, List<ExecutionProjectSituationVO>> dataMap = dataList.stream().collect(Collectors.groupingBy(ExecutionProjectSituationVO::getProjectType));
		List<ExecutionProjectSituationVO> fixedProjectSituationVOS = new ArrayList<>();
		List<ExecutionProjectSituationVO> stakeProjectSituationVOS = new ArrayList<>();
		if (dataMap.containsKey(1)){
			stakeProjectSituationVOS.addAll(dataMap.get(1));
			stakeProjectSituationVOS.add(subTotal(dataMap.get(1)));
		}

		if (dataMap.containsKey(2)){
			fixedProjectSituationVOS.addAll(dataMap.get(2));
			fixedProjectSituationVOS.add(subTotal(dataMap.get(2)));
		}
		result.setFixedProjectSituationVOS(fixedProjectSituationVOS);
		result.setStakeProjectSituationVOS(stakeProjectSituationVOS);
		return result;
	}

	@Override
	public List<ExecutionProjectSituationVO> statisticsProjectByProjectNature(BaseInvestmentExecutionDTO baseInvestmentExecutionDTO) {
		List<ExecutionProjectSituationVO> dataList = baseMapper
				.queryExecutionProjectByMonthNoProjectNatureName(baseInvestmentExecutionDTO.getFillingUnitIds(), baseInvestmentExecutionDTO.getFillingMonth());

		List<ExecutionProjectSituationVO> initList = init();
		if (CollectionUtil.isEmpty(dataList)){
			return initList;
		}
		Map<String, List<ExecutionProjectSituationVO>> dataMap = dataList.stream().collect(Collectors.groupingBy(ExecutionProjectSituationVO::getProjectNatureId));
		List<ExecutionProjectSituationVO> results = new ArrayList<>();
		for (ExecutionProjectSituationVO initVO : initList){
			if (dataMap.containsKey(initVO.getProjectNatureId())){
				List<ExecutionProjectSituationVO> voList = dataMap.get(initVO.getProjectNatureId());
				voList.get(0).setProjectNatureName(initVO.getProjectNatureName());
				results.addAll(voList);
				ExecutionProjectSituationVO subTotal = subTotal(voList);
				subTotal.setProjectNatureName(subTotal.getFillingUnitName());
				subTotal.setFillingUnitName(null);
				results.add(subTotal);
			}
		}
		return results;
	}

	@Override
	@Transactional(rollbackFor = RuntimeException.class)
	public String saveProjectExecution(String data){
		YthResult ythResult = new YthResult();
		//成功的id集合
		List<String> successIds = new ArrayList<>();
		//失败的id集合
		List<String> failIds = new ArrayList<>();
		//失败的原因
		List<String> failReasons = new ArrayList<>();
		//将json字符串转换成list
		List<BaseInvestmentExecution> dataList = JSON.parseArray(data, BaseInvestmentExecution.class);
		if (CollectionUtil.isNotEmpty(dataList)){
			Map<String, String> orgSourceMap = orgService.getSourceId();
			//根据datasourceIds 查询出所有的数据
			List<BaseInvestmentExecution> list = list(new LambdaQueryWrapper<BaseInvestmentExecution>().in(BaseInvestmentExecution::getDataSourceId, dataList.stream().map(BaseInvestmentExecution::getDataSourceId).toArray()));
			if (CollectionUtil.isNotEmpty(list)){
				//删除子集
				List<Long> ids = list.stream().map(BaseInvestmentExecution::getId).collect(Collectors.toList());
				effectiveInvestmentService.remove(new LambdaQueryWrapper<EffectiveInvestment>().in(EffectiveInvestment::getBaseInvestmentExecutionId, ids));
				fundProjectService.remove(new LambdaQueryWrapper<FundProject>().in(FundProject::getBaseInvestmentExecutionId, ids));
			}
			//如果数据库中有数据，就更新，没有就新增
			for (BaseInvestmentExecution entity:dataList){
				transfer(entity,orgSourceMap);
				//id重复略过
				if (CollectionUtil.isNotEmpty(list)){
					List<String> olIds = list.stream().map(BaseInvestmentExecution::getDataSourceId).collect(Collectors.toList());
					String dataSourceId = entity.getDataSourceId();
					//判断数据库中是否有数据
					if (olIds.contains(dataSourceId)){
						for (BaseInvestmentExecution oldEntity:list){
							if (dataSourceId.equals(oldEntity.getDataSourceId())){
								//判断status是否为0，如果是0，就更新，不是0，就不更新
								if (CheckStatus.checkCode(oldEntity.getStatus())){
									successIds.add(dataSourceId);
									entity.setId(oldEntity.getId());
									entity.setDataSource(YthConstant.DATA_NINGBO);
									submit(entity);
									list.remove(oldEntity);
									break;
								}else {
									failIds.add(dataSourceId);
									failReasons.add("dataSourceId:"+dataSourceId+"数据已提交且已经在流程中，无法更新");
									break;
								}
							}
						}
					}else {
						//如果数据库中没有数据，就新增
						entity.setDataSource(YthConstant.DATA_NINGBO);
						submit(entity);
						successIds.add(entity.getDataSourceId());
					}
				}else {
					//如果数据库中没有数据，就新增
					entity.setDataSource(YthConstant.DATA_NINGBO);
					submit(entity);
					successIds.add(entity.getDataSourceId());
				}
			}
		} else {
			failReasons.add("数据为空");
		}
		ythResult.setSuccessIds(successIds);
		ythResult.setFailIds(failIds);
		ythResult.setFailReason(StringUtils.join(failReasons, ";"));
		//ythResult转换成json字符串
		return JSON.toJSONString(ythResult);
	}

	private void transfer(BaseInvestmentExecution entity, Map<String, String> orgSourceMap){
		Optional.ofNullable(entity.getFilingUnitId()).ifPresent(m ->
				{
					String orgId = orgSourceMap.get(m);
					if (StringUtil.isNotBlank(orgId)){
						entity.setFilingUnitId(orgId);
						entity.setCreateCompanyId(orgId);
					}
				}
		);

	}

	private List<ExecutionProjectSituationVO> init(){
		Map<String, String> map = baseInfoService.getChildMap(ValueSetConstant.PROJECT_NATURE);
		List<ExecutionProjectSituationVO> initList = new ArrayList<>();
		map.forEach((k, v) -> {
			if (!v.contains("(旧)")){
				ExecutionProjectSituationVO situationVO = new ExecutionProjectSituationVO();
				situationVO.setProjectNatureId(k);
				situationVO.setProjectNatureName(v);
				initList.add(situationVO);
			}
		});
		initList.sort(Comparator.comparing(o -> Integer.valueOf(o.getProjectNatureId())));

		return initList;
	}

	private ExecutionProjectSituationVO subTotal(List<ExecutionProjectSituationVO> dataList){
		ExecutionProjectSituationVO subTotal = new ExecutionProjectSituationVO();
		subTotal.setFillingUnitName("累计");
		subTotal.setProjectName(String.valueOf(dataList.size()));
		for (ExecutionProjectSituationVO situationVO : dataList){
			subTotal.setPlanTotalInvestment(BigDecimalUtil.add(subTotal.getPlanTotalInvestment(), situationVO.getPlanTotalInvestment()));
			subTotal.setLastCompleteInvestment(BigDecimalUtil.add(subTotal.getLastCompleteInvestment(), situationVO.getLastCompleteInvestment()));
			subTotal.setCompleteInvestment(BigDecimalUtil.add(subTotal.getCompleteInvestment(), situationVO.getCompleteInvestment()));
		}
		return subTotal;
	}

}
